#!/usr/bin/python
# server.py
# Copyright (C) Vincenzo Tilotta 2011 <tailot@gmail.com>
#
# server.py is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# server.py is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details.

# You should have received a copy of the GNU General Public License along
# with this program.  If not, see <http://www.gnu.org/licenses/>.
import sys, os, socket,time, random, threading, filecmp, warnings
from OpenSSL import SSL
from util import *
from defs import *
warnings.filterwarnings("ignore")

def start(info):
	#Autenticazione del client
	challenge = ''
	if AUTHENABLE:
		auth=(info[0].recv(49)).split("\n")
		if(auth[0] == 'login'):
			try:
				userpath = PATHAUTHUSER+"/"+auth[1]
				if(os.path.exists(userpath)):
					pwd = fread(userpath+"/"+"pw.pubkey")
					#usata anche come password per VNC
					challenge = str(random.randint(1000000,99999999))
					fput(userpath+"/"+challenge,challenge)
					os.system("cat "+userpath+"/"+challenge+" | ./../vncpasswd -f > "+userpath+"/"+challenge+"VNC")
					os.system("openssl rsautl -encrypt -in "+userpath+"/"+challenge+"VNC -pubin -inkey "+userpath+"/pw.pubkey -out "+userpath+"/msg_"+challenge+"")
					msgsend = fread(userpath+"/msg_"+challenge)
					info[0].write(msgsend)
					rec_chal = info[0].recv(len(challenge))
					fput(userpath+"/"+challenge+"RCV",rec_chal)
					if not filecmp.cmp(userpath+"/"+challenge+"RCV",userpath+"/"+challenge+"VNC"):
						info[0].close()
						return
					else:
						#pulisco file
						os.remove(userpath+"/"+challenge)
						os.remove(userpath+"/msg_"+challenge)
						os.remove(userpath+"/"+challenge+"VNC")
						os.remove(userpath+"/"+challenge+"RCV")
				else:
					info[0].close()
					return
			except:
				if DEBUG:
					print "Mancata autenticazione per "+info[1][0]
				info[0].close()
				return
		else:
			info[0].close()
			return
	if DEBUG:
		print "Client "+info[1][0]+" AUTENTICATO!"
	request = (info[0].recv(10)).split("_")
	#Sondare carico di lavoro dei nodi
	cpu_node = []
	cpu_usage = ''
	for nodo in LISTNODE:
		cpu_usage = os.popen("ssh "+nodo+" ps aux | awk {'sum+=$3;print sum'} | tail -n 1").read()
		if isnumeric(cpu_usage):
			cpu_node.append({int(cpu_usage.split(".")[0]) : nodo})
	cpu_node.sort()
	if DEBUG:
		print "Lista del carico sui nodi ATTUALE"
		print cpu_node
	#rimuovo i nodi terminali dalla coda	
	for i in range(0,len(cpu_node)-1):
		if i >= MAXNODES:
			cpu_node.pop(i)
	#preparo messaggio con nodi ordinati per cpu usage.
	msg_cpu = ''
	for i in range(0,len(cpu_node)):
		#node_extract = cpu_node[i].split("_")
		for j in cpu_node[i].keys():
			msg_cpu = msg_cpu + cpu_node[i][j]
			if i != len(cpu_node) - 1:
				msg_cpu = msg_cpu + "\n"
	#invio messaggio cpu_usage
	info[0].write(msg_cpu)
	#ricevo nodo piu' vicino al client
	node_win = info[0].recv(20)
	if int(request[1]) == 1:
		os.system("./../onevm.py deploy 0 "+str(LISTNODE.index(node_win))+" "+challenge+" > /tmp/"+info[1][0])
		info_listen = fread("/tmp/"+info[1][0])
		info_listen = (info_listen.replace("vncviewer ","").replace("\n","")).split(":")
		if DEBUG:
			print "./onevm.py deploy 0 "+str(LISTNODE.index(node_win))+" "+challenge
		info[0].write("vncviewer "+node_win+":"+info_listen[1])
		#chiudo la connessione con il client connesso
		info[0].close()
		chance = 0
		while 1:
			time.sleep(10)
			free_vm = os.popen("ssh "+node_win+" netstat -nat | grep ESTABLISHED | awk {'print $4'} | tr ':' ' ' | awk {'print $2'} | grep "+str(5900+int(info_listen[1]))).read()
			if free_vm.replace("\n","").isdigit():
				chance = 0
			else:
				chance = chance + 1
				
			if chance == 3:
				if DEBUG:
					print "Chiudo la VM per "+info[1][0]
				os.system("./../onevm.py remove "+info_listen[1]+" "+str(LISTNODE.index(node_win)))
				sys.exit()
def main():
	#import chiave privata e certificato
	context = SSL.Context(SSL.SSLv23_METHOD)
	context.use_privatekey_file('key')
	context.use_certificate_file('cert')

	s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	s = SSL.Connection(context, s)
	s.bind(('', PORTSERVER))
	s.listen(5)
	
	while True:
		(connection, address) = s.accept()
		thread1 = threading.Thread( target=start, args=((connection, address),) )
		thread1.start()

if __name__ == "__main__":
    sys.exit(main())
